/*
 * @Author: mayijun
 * @Date: 2022-04-27 14:41:12
 * @LastEditors: mayijun
 * @LastEditTime: 2022-07-14 13:44:03
 */
import {
  defineComponent,
  ref,
  reactive,
  onMounted,
  PropType,
  nextTick
} from 'vue';
import { CaretBottom, ArrowRight } from '@element-plus/icons-vue';
import './index.scss';
import API from '@/services';
import G6 from '@antv/g6';
import rightArrow from '@/assets/images/right.svg';

//指标关联组件
const IndexCorrelation = defineComponent({
  name: 'IndexCorrelation',
  components: { CaretBottom, ArrowRight },
  props: {
    id: {
      type: String as PropType<string>
    }
  },
  setup(props) {
    const containerBoxRef = ref();

    const state = reactive({
      clickShow: false, //单击效果
      nodeMaxWidth: 0, //节点最大宽度，所有节点宽度统一
      bgColor: '#ffffff',
      g6Data: {} as any
      // g6Data: {
      //   nodes: [{
      //     id: "7",
      //     cnName: "近7天用户注册",
      //     metricsTypeName: "原子",
      //     metricsType: 1,
      //     width: 7 * 20,
      //   }, {
      //     id: "8",
      //     cnName: "没有",
      //     metricsTypeName: "派生",
      //     metricsType: 2,
      //     width: 2 * 20,
      //   }, {
      //     id: "1",
      //     cnName: "系统管理员",
      //     metricsTypeName: "原子",
      //     metricsType: 1,
      //     width: 5 * 20,
      //   }, {
      //     id: "2",
      //     cnName: "zyz",
      //     metricsTypeName: "派生",
      //     metricsType: 2,
      //     width: 3 * 20,
      //   }, {
      //     id: "3",
      //     cnName: "张三",
      //     metricsTypeName: "衍生",
      //     metricsType: 3,
      //     width: 2 * 20,
      //   }, {
      //     id: "4",
      //     cnName: "李四",
      //     metricsTypeName: "衍生",
      //     metricsType: 3,
      //     width: 2 * 20,
      //   }, {
      //     id: "5",
      //     cnName: "王五",
      //     metricsTypeName: "衍生",
      //     metricsType: 3,
      //     width: 2 * 20,
      //   }, {
      //     id: "6",
      //     cnName: "老六",
      //     metricsTypeName: "衍生",
      //     metricsType: 3,
      //     width: 2 * 20,
      //   }],
      //   //节点关联关系
      //   edges: [{
      //     source: "1",
      //     target: "2",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "1",
      //     target: "6",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "2",
      //     target: "3",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "2",
      //     target: "4",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "2",
      //     target: "5",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "3",
      //     target: "6",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "4",
      //     target: "6",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "5",
      //     target: "6",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }, {
      //     source: "7",
      //     target: "8",
      //     type: 'polyline',
      //     style: {
      //       endArrow: {
      //         path: G6.Arrow.triangle(),
      //         fill: '#396EFE',
      //         lineDash: [0],
      //       },
      //       lineDash: [2, 2, 2],
      //       stroke: '#396EFE',
      //     },
      //     label: "四则运算",
      //   }]

      // } as any,
    });

    //查询关联指标
    let getRelation = async (id: any) => {
      const { code, data } = await API.metricsLibrary.getRelationById({ id });
      if (code === 200 && data) {
        //节点数组
        let nodes = data.nodes;
        let maxWidth = 0;
        nodes?.map((item: any) => {
          item.metricsTypeName = item.metricsTypeName.substring(0, 2);
          item.width = item.cnName.length * 16;
          if (item.width > maxWidth) {
            maxWidth = item.width;
          }
        });
        state.nodeMaxWidth = maxWidth;

        //边数组
        let links = data.links;
        links?.map((item: any) => {
          item.type = 'polyline';
          item.style = {
            endArrow: {
              path: G6.Arrow.triangle(),
              fill: '#396EFE',
              lineDash: [0]
            },
            lineDash: [2, 2, 2],
            stroke: '#396EFE'
          };
          let node = nodes?.find((obj: any) => obj.id == item.target);
          item.label = node?.metricsType == 2 ? '元素拼接' : '四则运算';
        });

        //整理数据对象
        let g6Data: any = {
          nodes: nodes,
          edges: links
        };
        state.g6Data = g6Data;

        //注册自定义节点
        registerNode();
        nextTick(() => {
          getContainerBox();
        });
      }
    };

    //打开新的指标详情
    const openNewDetail = (id: any) => {
      window.open(
        `${
          process.env.VUE_APP_PUBLICPATH === '/'
            ? ''
            : process.env.VUE_APP_PUBLICPATH
        }#/market/detail?id=${id}`,
        '_blank'
      );
    };

    //获取指标对应的颜色
    const getIndexColor = (type: number) => {
      if (type == 1) {
        return {
          color: '#3C6EFF',
          bgColor: 'rgba(60,110,255,0.2)'
        };
      } else if (type == 2) {
        return {
          color: '#F5872C',
          bgColor: 'rgba(245,135,44,0.2)'
        };
      } else {
        return {
          color: '#CE5FE4',
          bgColor: 'rgba(206,95,228,0.2)'
        };
      }
    };

    //查找上级的所有元素
    const findSourceNodeList = (
      currentId: any,
      graph: any,
      sourceNodeList: any[],
      nodeList: any[]
    ) => {
      sourceNodeList.map((item) => {
        nodeList.push(item);
        item._cfg.edges.map((eg: any) => {
          //有关联的展示
          if (eg._cfg.model.target == currentId) {
            //设置箭头颜色
            eg._cfg.keyShape.attrs.endArrow.fill = '#ffffff';
            graph.setItemState(eg, 'actived', true);
            //设置label的显示
            eg._cfg.model.labelCfg.style.opacity = 1;
            eg._cfg.model.labelCfg.style.background.opacity = 1;
            graph.updateItem(eg, eg._cfg.model);
          }
        });
        let sourceList = graph.getNeighbors(item, 'source');
        if (sourceList.length > 0) {
          findSourceNodeList(item._cfg.id, graph, sourceList, nodeList);
        }
      });
    };

    //查找下级的所有元素
    const findTargetNodeList = (
      currentId: any,
      graph: any,
      targetNodeList: any[],
      nodeList: any[]
    ) => {
      targetNodeList.map((item) => {
        nodeList.push(item);
        item._cfg.edges.map((eg: any) => {
          //有关联的展示
          if (eg._cfg.model.source == currentId) {
            //设置箭头颜色
            eg._cfg.keyShape.attrs.endArrow.fill = '#ffffff';
            graph.setItemState(eg, 'actived', true);
            //设置label的显示
            eg._cfg.model.labelCfg.style.opacity = 1;
            eg._cfg.model.labelCfg.style.background.opacity = 1;
            graph.updateItem(eg, eg._cfg.model);
          }
        });
        let targetList = graph.getNeighbors(item, 'target');
        if (targetList.length > 0) {
          findTargetNodeList(item._cfg.id, graph, targetList, nodeList);
        }
      });
    };

    //查找不在路径上的元素
    const findNoPathNodeList = (graph: any, nodeList: any[]) => {
      //获取所有节点
      let all = graph.getNodes();
      return all.filter((item: any) => {
        let isHas = nodeList.some((child) => child._cfg.id == item._cfg.id);
        if (!isHas) {
          return item;
        }
      });
    };

    //绘制关系图
    const getContainerBox = async () => {
      const width = containerBoxRef.value.clientWidth;
      const height = containerBoxRef.value.clientHeight;
      let rectWidth = state.nodeMaxWidth > 150 ? state.nodeMaxWidth : 150;
      const graph = new G6.Graph({
        container: 'containerBox',
        width,
        height,
        //fitView: true,
        //linkCenter: true,
        layout: {
          type: 'dagre',
          rankdir: 'LR',
          preventOverlap: true,
          //align: 'UL',
          //nodesep: 100,
          ranksepFunc: (d: any) => {
            return rectWidth;
          },
          controlPoints: true
        },
        defaultNode: {
          type: 'nodeItem'
        },
        defaultEdge: {
          labelCfg: {
            autoRotate: true,
            position: 'end',
            refX: -rectWidth / 2 + 20,
            refY: 20,
            style: {
              opacity: 0,
              fill: '#ffffff',
              background: {
                opacity: 0,
                fill: 'rgba(0,0,0,0.2)',
                padding: [6, 4, 6, 4],
                radius: 2,
                lineWidth: 1
              }
            }
          }
        },
        nodeStateStyles: {
          noActived: {
            'rect-shape-1': {
              opacity: 0.4
            }
          }
        },
        edgeStateStyles: {
          actived: {
            stroke: '#ffffff'
          },
          noActived: {
            opacity: 0.4
          }
        },
        modes: {
          default: ['drag-canvas', 'zoom-canvas', 'click-select']
        }
      });
      graph.data(state.g6Data);
      graph.render();

      //节点事件监听
      graph.on('node:click', (ev) => {
        const shape = ev.target;
        const item: any = ev.item;
        //点击右侧图片
        if (shape.cfg.type == 'image') {
          //打开新的指标详情
          openNewDetail(item?._cfg?.id);
        } else if (shape.cfg.type == 'text' || shape.cfg.type == 'rect') {
          //点击节点
          //背景色
          state.bgColor = 'rgba(0,0,0,0.7)';

          if (item?._cfg?.id) {
            //节点样式
            //查找上级
            let sourceNodeList = graph.getNeighbors(item._cfg.id, 'source');
            //查找下级
            let targetNodeList = graph.getNeighbors(item._cfg.id, 'target');
            //当前路径下的所有元素
            let nodeList: any[] = [];
            //加入当前对象
            nodeList.push(item);

            findSourceNodeList(item._cfg.id, graph, sourceNodeList, nodeList);
            findTargetNodeList(item._cfg.id, graph, targetNodeList, nodeList);
            let npPathNodeList = findNoPathNodeList(graph, nodeList);
            //设置节点样式
            npPathNodeList.map((obj: any) => {
              obj._cfg.edges.map((eg: any) => {
                graph.setItemState(eg, 'noActived', true);
              });
              graph.setItemState(obj, 'noActived', true);
            });
            console.log(nodeList);
          }
        }
      });
      graph.on('click', (evt) => {
        state.bgColor = '#ffffff';
        //清楚所有节点状态
        let allNodes = graph.getNodes();
        let allEdges = graph.getEdges();
        allNodes.map((item) => {
          graph.clearItemStates(item);
        });
        allEdges.map((item: any) => {
          if (item && item._cfg && item._cfg.keyShape) {
            //@ts-ignore
            item._cfg.keyShape.attrs.endArrow.fill = '#396EFE';
          }
          graph.clearItemStates(item);

          //设置label的显示
          item._cfg.model.labelCfg.style.opacity = 0;
          item._cfg.model.labelCfg.style.background.opacity = 0;
          graph.updateItem(item, item._cfg.model);
        });
      });
    };

    //自定义节点
    const registerNode = () => {
      G6.registerNode(
        'nodeItem',
        {
          drawShape(cfg: any, group: any) {
            //指标名称内容宽度
            let rectWidth =
              state.nodeMaxWidth > 150 ? state.nodeMaxWidth + 50 : 200;
            let rectHeight = 50;
            //节点轮廓
            const rect = group.addShape('rect', {
              attrs: {
                x: -75,
                y: -25,
                width: rectWidth, //指标内容宽度+指标类型宽度
                height: rectHeight,
                radius: 3,
                stroke: '#E8EBF2',
                fill: '#ffffff',
                lineWidth: 1
              },
              name: 'rect-shape',
              zIndex: 1
            });

            group.addShape('rect', {
              attrs: {
                x: -75,
                y: -25,
                width: rectWidth, //指标内容宽度+指标类型宽度
                height: rectHeight,
                radius: 3,
                stroke: '#000000',
                fill: '#000000',
                lineWidth: 1,
                opacity: 0
              },
              name: 'rect-shape-1',
              zIndex: 6
            });

            //类型名称展示
            if (cfg.metricsTypeName) {
              //获取颜色对象
              let colorItem = getIndexColor(cfg.metricsType);
              let typeRect = group.addShape('rect', {
                attrs: {
                  fill: colorItem.bgColor,
                  radius: 2,
                  cursor: 'pointer'
                },
                name: 'ip-container-shape',
                zIndex: 3
              });
              let typeText = group.addShape('text', {
                attrs: {
                  text: cfg.metricsTypeName,
                  x: -45,
                  y: 0,
                  fill: colorItem.color,
                  fontSize: 12,
                  textAlign: 'center',
                  textBaseline: 'middle'
                },
                name: 'type-shape',
                zIndex: 4
              });
              const ipBBox = typeText.getBBox();
              //边框宽度和位置计算
              typeRect.attr({
                x: -45 - (ipBBox.width + 8) / 2,
                y: (-12 - 10) / 2,
                width: ipBBox.width + 8,
                height: ipBBox.height + 10
              });
            }

            //指标名称展示
            if (cfg.cnName) {
              group.addShape('text', {
                attrs: {
                  text: cfg.cnName,
                  x: -15,
                  y: 0,
                  width: 100,
                  fill: '#396EFE',
                  fontSize: 14,
                  textAlign: 'left',
                  textBaseline: 'middle'
                },
                name: 'text-shape',
                zIndex: 2
              });
            }

            //右侧箭头展示
            group.addShape('image', {
              attrs: {
                x: rectWidth - 100,
                y: -5,
                size: 48,
                img: rightArrow,
                cursor: 'pointer'
              },
              name: 'text-shape',
              zIndex: 10
            });

            group.sort();
            return rect;
          }
        },
        'single-node'
      );
    };

    onMounted(() => {
      getRelation(props.id);
    });

    return () => {
      return (
        <div
          id="containerBox"
          ref={containerBoxRef}
          class="container-box"
          style={{ backgroundColor: state.bgColor }}
        ></div>
      );
    };
  }
});

export default IndexCorrelation;
